# encoding: utf-8
# @File  : heartbeat.py
# @Author: shaoyun
# @Date  :  2025/05/11
import asyncio
import logging
from datetime import datetime
from typing import Dict, Any, Optional

import httpx

from app.core.config import settings

logger = logging.getLogger("worker.heartbeat")


class HeartbeatManager:
    """心跳管理器"""

    def __init__(self, node_id: str, master_url: str):
        self.node_id = node_id
        self.master_url = master_url
        self.running = False
        self.last_success = None
        self.interval = settings.NODE_HEARTBEAT_INTERVAL

    async def start(self):
        """启动心跳管理器"""
        if self.running:
            logger.warning("Heartbeat manager is already running")
            return

        self.running = True
        logger.info(f"Starting heartbeat manager for node {self.node_id}")

        asyncio.create_task(self._heartbeat_loop())

    async def stop(self):
        """停止心跳管理器"""
        logger.info("Stopping heartbeat manager")
        self.running = False

    async def _heartbeat_loop(self):
        """心跳循环"""
        while self.running:
            try:
                success = await self.send_heartbeat()
                if success:
                    self.last_success = datetime.utcnow()

                await asyncio.sleep(self.interval)
            except Exception as e:
                logger.error(f"Error in heartbeat loop: {e}")
                await asyncio.sleep(5)  # 出错后等待较短时间再次尝试

    async def send_heartbeat(self) -> bool:
        """发送心跳"""
        url = f"{self.master_url}/api/v1/nodes/{self.node_id}/heartbeat"
        timestamp = int(datetime.utcnow().timestamp())

        try:
            async with httpx.AsyncClient() as client:
                response = await client.post(
                    url,
                    json={
                        "node_id": self.node_id,
                        "timestamp": timestamp
                    },
                    timeout=5.0
                )

                if response.status_code != 200:
                    logger.warning(f"Failed to send heartbeat: {response.status_code} - {response.text}")
                    return False

                logger.debug("Heartbeat sent successfully")
                return True
        except Exception as e:
            logger.error(f"Error sending heartbeat: {e}")
            return False

    def get_status(self) -> Dict[str, Any]:
        """获取心跳状态"""
        now = datetime.utcnow()

        return {
            "running": self.running,
            "last_success": self.last_success.isoformat() if self.last_success else None,
            "time_since_last": (now - self.last_success).total_seconds() if self.last_success else None,
            "status": "healthy" if self.last_success and (
                        now - self.last_success).total_seconds() < self.interval * 2 else "unhealthy"
        }